﻿//=====================================================================================================
// LocalizationLibrary
// The Localization Library is a collection of reusable software components that provide 
// support for localization. This library enables you to localize WPF, Silverlight and WP7 applications.
// (http://localizationlibrary.codeplex.com)
//=====================================================================================================
// Author: Nicola Gallo (Website: www.nicola.gallo.name, Email: nicolagmt@hotmail.it) 
//=====================================================================================================

namespace SLS.ExClassLib.Loc
{
    //.NET References
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Security.Policy;  //for Evidence object

    /// <summary>
    /// Implements a reflection cache.
    /// </summary>
    public class ReflectionCache
    {
        //Fields

        private Dictionary<String, AssemblyRef> _processedAssemblies;
        private Dictionary<String, TypeRef> _processedTypes;
        private  Assembly[] DomainAssemblies = null;
        public Dictionary<String, AssemblyRef> CurrentDomainAssemblies=new Dictionary<string,AssemblyRef>();
        AppDomain currentDomain = AppDomain.CurrentDomain;
        //Provide the current application domain evidence for the assembly.
        Evidence asEvidence;

        //Constructors

        /// <summary>
        /// Default constructor. Is a private constructor.
        /// </summary>
        private ReflectionCache() 
        {
            asEvidence = currentDomain.Evidence;
        }
        public void RefreshCurrentDomain()
        {
            DomainAssemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in DomainAssemblies)
            {
                AddToCurrentDomain(assembly);
            }
        }
        public void AddToCurrentDomain(Assembly assembly)
        {
            AssemblyRef assemblyRef = null;
            string Name = "";
            Name = assembly.GetName().Name;
            if (!CurrentDomainAssemblies.ContainsKey(Name))
            {
                assemblyRef = new AssemblyRef(assembly);
                this.CurrentDomainAssemblies.Add(Name, assemblyRef);               
            }
        }
        //Properties

        /// <summary>
        /// Gets a dictionary that contains the assemblies whom have been processed by <see cref="ReflectionCache"/>.
        /// </summary>
        public Dictionary<String, AssemblyRef> ProcessedAssemblies 
        {
            get 
            {
                if (this._processedAssemblies == null)
                {
                    this._processedAssemblies = new Dictionary<String, AssemblyRef>();
                }
                return this._processedAssemblies;
            }
        }

        /// <summary>
        /// Gets processd types.
        /// </summary>
        protected Dictionary<String, TypeRef> ProcessedTypes
        {
            get 
            {
                if (this._processedTypes == null)
                {
                    this._processedTypes = new Dictionary<string, TypeRef>();
                }
                return this._processedTypes;
            } 
        }

        //Methods

        /// <summary>
        /// Creates a new instance of the <see cref="ReflectionCache"/>.
        /// </summary>
        /// <returns>Returns a new instance of the <see cref="ReflectionCache"/>.</returns>
        public static ReflectionCache Create() 
        {
            return new ReflectionCache();
        }

        /// <summary>
        /// Load the input <paramref name="assembly" parameter./>.
        /// </summary>
        /// <param name="assembly">Defines the assembly that should be processed.</param>
        /// <returns>Returns the wrapped assembly.</returns>
        public AssemblyRef LoadAssembly(Assembly assembly) 
        {
            AssemblyRef assemblyRef = null;
            string Name = assembly.GetName().Name;
            if (assembly != null)
            {
                if (this.ProcessedAssemblies.ContainsKey(Name))
                {
                    assemblyRef = this.ProcessedAssemblies[Name];
                }
                else
                {
                    assemblyRef = new AssemblyRef(assembly);
                    this.ProcessedAssemblies.Add(Name, assemblyRef);
                }
            }
            return assemblyRef;
        }

        /// <summary>
        /// Gets all processed assemblies.
        /// </summary>
        /// <returns>Array of <see cref="AssemblyRef"/> that contains all processed assemblies.</returns>
        public AssemblyRef[] GetAllAssemblyRef() 
        {
            return this.ProcessedAssemblies.Values.ToArray();
        }

        /// <summary>
        /// If the input <paramref name="assembly"/> has been already processed then return the <see cref="AssemblyRef"/>,
        /// otherwise return null.
        /// </summary>
        /// <param name="assembly">Assembly.</param>
        /// <returns>
        /// If the input <paramref name="assembly"/> has been already processed then return the <see cref="AssemblyRef"/>,
        /// otherwise return null.
        /// </returns>
        public AssemblyRef GetAssemblyRef(Assembly assembly)
        {
            AssemblyRef retVal = null;
            if ((assembly != null) && (this.ProcessedAssemblies.ContainsKey(assembly.FullName)))
            {
                retVal = this.ProcessedAssemblies[assembly.FullName];
            }
            return retVal;
        }

        /// <summary>
        /// Load the input <paramref name="type" parameter./>.
        /// </summary>
        /// <param name="type">Defines the type that should be processed.</param>
        /// <returns>Returns the wrapped type.</returns>
        public TypeRef LoadType(Type type)
        {
            TypeRef typeRef = null;
            if (type != null)
            {
                if (this.ProcessedTypes.ContainsKey(type.FullName))
                {
                    typeRef = this.ProcessedTypes[type.FullName];
                }
                else
                {
                    typeRef = new TypeRef(type);
                    this.ProcessedTypes.Add(type.FullName, typeRef);
                }
            }
            return typeRef;
        }

        /// <summary>
        /// If the input <paramref name="type"/> has been already processed then return the <see cref="TypeRef"/>,
        /// otherwise return null.
        /// </summary>
        /// <param name="type">Assembly.</param>
        /// <returns>
        /// If the input <paramref name="type"/> has been already processed then return the <see cref="TypeRef"/>,
        /// otherwise return null.
        /// </returns>
        public TypeRef GetTypeRef(Type type)
        {
            TypeRef retVal = null;
            if ((type != null) && (this.ProcessedTypes.ContainsKey(type.FullName)))
            {
                retVal = this.ProcessedTypes[type.FullName];
            }
            return retVal;
        }
    }
}